package com.example.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.example.dto.PostgraduateInfoDTO;
import com.example.entity.PostgraduateInfoDO;
import com.example.exception.BusinessException;
import com.example.mapper.PostgraduateInfoMapper;
import com.example.query.PostgraduateInfoQuery;
import com.example.service.UserService;
import com.example.service.impl.PostgraduateInfoServiceImpl;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

class PostgraduateInfoServiceTest {

    @Mock
    private PostgraduateInfoMapper postgraduateInfoMapper;

    @Mock
    private UserService userService;

    @InjectMocks
    private PostgraduateInfoServiceImpl postgraduateInfoService;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    void testAddPostgraduateInfo_UserDoesNotExist() {
        PostgraduateInfoDTO postgraduateInfoDTO = new PostgraduateInfoDTO();
        postgraduateInfoDTO.setUserId(1);
        postgraduateInfoDTO.setExperience("Some experience");
        postgraduateInfoDTO.setTips("Some tips");
        postgraduateInfoDTO.setShareStatus(true);

        when(userService.exists(any())).thenReturn(false);

        assertThrows(BusinessException.class, () -> postgraduateInfoService.addPostgraduateInfo(postgraduateInfoDTO));
        verify(postgraduateInfoMapper, never()).insert(any());
    }

    @Test
    void testAddPostgraduateInfo_Success() {
        PostgraduateInfoDTO postgraduateInfoDTO = new PostgraduateInfoDTO();
        postgraduateInfoDTO.setUserId(1);
        postgraduateInfoDTO.setExperience("Some experience");
        postgraduateInfoDTO.setTips("Some tips");
        postgraduateInfoDTO.setShareStatus(true);

        when(userService.exists(any())).thenReturn(true);
        when(postgraduateInfoMapper.insert(any())).thenReturn(1);

        Boolean result = postgraduateInfoService.addPostgraduateInfo(postgraduateInfoDTO);
        assertTrue(result);
        verify(postgraduateInfoMapper).insert(any());
    }

    @Test
    void testUpdatePostgraduateInfo_InfoDoesNotExist() {
        PostgraduateInfoDTO postgraduateInfoDTO = new PostgraduateInfoDTO();
        postgraduateInfoDTO.setInfoId(1);
        postgraduateInfoDTO.setUserId(1);
        postgraduateInfoDTO.setExperience("Updated experience");
        postgraduateInfoDTO.setTips("Updated tips");
        postgraduateInfoDTO.setShareStatus(false);

        when(postgraduateInfoMapper.selectById(any())).thenReturn(null);

        assertThrows(BusinessException.class, () -> postgraduateInfoService.updatePostgraduateInfo(postgraduateInfoDTO));
        verify(postgraduateInfoMapper, never()).updateById(any());
    }

    @Test
    void testUpdatePostgraduateInfo_UserDoesNotExist() {
        PostgraduateInfoDTO postgraduateInfoDTO = new PostgraduateInfoDTO();
        postgraduateInfoDTO.setInfoId(1);
        postgraduateInfoDTO.setUserId(1);
        postgraduateInfoDTO.setExperience("Updated experience");
        postgraduateInfoDTO.setTips("Updated tips");
        postgraduateInfoDTO.setShareStatus(false);

        PostgraduateInfoDO existingInfo = new PostgraduateInfoDO();
        existingInfo.setInfoId(1);
        existingInfo.setUserId(1);
        existingInfo.setExperience("Old experience");
        existingInfo.setTips("Old tips");
        existingInfo.setShareStatus(true);

        when(postgraduateInfoMapper.selectById(any())).thenReturn(existingInfo);
        when(userService.exists(any())).thenReturn(false);

        assertThrows(BusinessException.class, () -> postgraduateInfoService.updatePostgraduateInfo(postgraduateInfoDTO));
        verify(postgraduateInfoMapper, never()).updateById(any());
    }

    @Test
    void testUpdatePostgraduateInfo_Success() {
        PostgraduateInfoDTO postgraduateInfoDTO = new PostgraduateInfoDTO();
        postgraduateInfoDTO.setInfoId(1);
        postgraduateInfoDTO.setUserId(1);
        postgraduateInfoDTO.setExperience("Updated experience");
        postgraduateInfoDTO.setTips("Updated tips");
        postgraduateInfoDTO.setShareStatus(false);

        PostgraduateInfoDO existingInfo = new PostgraduateInfoDO();
        existingInfo.setInfoId(1);
        existingInfo.setUserId(1);
        existingInfo.setExperience("Old experience");
        existingInfo.setTips("Old tips");
        existingInfo.setShareStatus(true);

        when(postgraduateInfoMapper.selectById(any())).thenReturn(existingInfo);
        when(userService.exists(any())).thenReturn(true);
        when(postgraduateInfoMapper.updateById(any())).thenReturn(1);

        Boolean result = postgraduateInfoService.updatePostgraduateInfo(postgraduateInfoDTO);
        assertTrue(result);
        verify(postgraduateInfoMapper).updateById(any());
    }

    @Test
    void testDeletePostgraduateInfo_InfoDoesNotExist() {
        when(postgraduateInfoMapper.selectById(any())).thenReturn(null);

        assertThrows(BusinessException.class, () -> postgraduateInfoService.deletePostgraduateInfo(1));
        verify(postgraduateInfoMapper, never()).deleteById(any());
    }

    @Test
    void testDeletePostgraduateInfo_Success() {
        PostgraduateInfoDO existingInfo = new PostgraduateInfoDO();
        existingInfo.setInfoId(1);
        existingInfo.setUserId(1);
        existingInfo.setExperience("Some experience");
        existingInfo.setTips("Some tips");
        existingInfo.setShareStatus(true);

        when(postgraduateInfoMapper.selectById(any())).thenReturn(existingInfo);
        when(postgraduateInfoMapper.deleteById(any())).thenReturn(1);

        Boolean result = postgraduateInfoService.deletePostgraduateInfo(1);
        assertTrue(result);
        verify(postgraduateInfoMapper).deleteById(any());
    }

    @Test
    void testGetPostgraduateInfos_NoUserId() {
        QueryWrapper<PostgraduateInfoDO> wrapper = Wrappers.query();
        wrapper.eq("share_status", true);

        List<PostgraduateInfoDO> expectedInfos = new ArrayList<>();
        expectedInfos.add(new PostgraduateInfoDO(1, 1, "Experience 1", "Tips 1", true, 1, new Date(), 1, new Date()));
        expectedInfos.add(new PostgraduateInfoDO(2, 2, "Experience 2", "Tips 2", true, 2, new Date(), 2, new Date()));

        when(postgraduateInfoMapper.selectList(wrapper)).thenReturn(expectedInfos);

        PostgraduateInfoQuery query = new PostgraduateInfoQuery();
        List<PostgraduateInfoDO> result = postgraduateInfoService.getPostgraduateInfos(query);

        assertEquals(expectedInfos, result);
        verify(postgraduateInfoMapper).selectList(wrapper);
    }

    @Test
    void testGetPostgraduateInfos_WithUserId() {
        QueryWrapper<PostgraduateInfoDO> wrapper = Wrappers.query();
        wrapper.eq("user_id", 1);

        List<PostgraduateInfoDO> expectedInfos = new ArrayList<>();
        expectedInfos.add(new PostgraduateInfoDO(1, 1, "Experience 1", "Tips 1", true, 1, new Date(), 1, new Date()));

        when(postgraduateInfoMapper.selectList(wrapper)).thenReturn(expectedInfos);

        PostgraduateInfoQuery query = new PostgraduateInfoQuery();
        query.setUserId(1);
        List<PostgraduateInfoDO> result = postgraduateInfoService.getPostgraduateInfos(query);

        assertEquals(expectedInfos, result);
        verify(postgraduateInfoMapper).selectList(wrapper);
    }

    @Test
    void testImportPostgraduateInfo_FileDoesNotExist() {
        when(postgraduateInfoService.checkFileExists(any())).thenReturn(false);

        assertThrows(BusinessException.class, () -> postgraduateInfoService.importPostgraduateInfo(1));
    }

    @Test
    void testImportPostgraduateInfo_Success() {
        when(postgraduateInfoService.checkFileExists(any())).thenReturn(true);

        Boolean result = postgraduateInfoService.importPostgraduateInfo(1);
        assertTrue(result);
    }

    @Test
    void testExportPostgraduateInfos_NoInfoIds() {
        QueryWrapper<PostgraduateInfoDO> wrapper = Wrappers.query();
        wrapper.eq("share_status", true);

        List<PostgraduateInfoDO> expectedInfos = new ArrayList<>();
        expectedInfos.add(new PostgraduateInfoDO(1, 1, "Experience 1", "Tips 1", true, 1, new Date(), 1, new Date()));
        expectedInfos.add(new PostgraduateInfoDO(2, 2, "Experience 2", "Tips 2", true, 2, new Date(), 2, new Date()));

        when(postgraduateInfoMapper.selectList(wrapper)).thenReturn(expectedInfos);

        PostgraduateInfoDTO dto = new PostgraduateInfoDTO();
        List<PostgraduateInfoDO> result = postgraduateInfoService.exportPostgraduateInfos(dto.getInfoIds());

        assertEquals(expectedInfos, result);
        verify(postgraduateInfoMapper).selectList(wrapper);
    }

    @Test
    void testExportPostgraduateInfos_WithInfoIds() {
        QueryWrapper<PostgraduateInfoDO> wrapper = Wrappers.query();
        wrapper.in("info_id", List.of(1, 2));

        List<PostgraduateInfoDO> expectedInfos = new ArrayList<>();
        expectedInfos.add(new PostgraduateInfoDO(1, 1, "Experience 1", "Tips 1", true, 1, new Date(), 1, new Date()));
        expectedInfos.add(new PostgraduateInfoDO(2, 2, "Experience 2", "Tips 2", true, 2, new Date(), 2, new Date()));

        when(postgraduateInfoMapper.selectList(wrapper)).thenReturn(expectedInfos);

        PostgraduateInfoDTO dto = new PostgraduateInfoDTO();
        dto.setInfoIds(List.of(1, 2));
        List<PostgraduateInfoDO> result = postgraduateInfoService.exportPostgraduateInfos(dto.getInfoIds());

        assertEquals(expectedInfos, result);
        verify(postgraduateInfoMapper).selectList(wrapper);
    }
}